home *** CD-ROM | disk | FTP | other *** search
- //-------------------------------------------------------------------------
- //
- // Fractal Landscape Generator v1.3
- // Copyright (c) 1992 Steve Anger
- // This program is freely distributable
- //
- // FRGEN is a utility to generate fractal landscapes and shapes using
- // successive triangle sub-division. The fractal data can be output as
- // POV-Ray 1.0 or Vivid 2.0 scene description files or as raw triangle
- // data.
- //
- // Notes for compiling under Turbo/Borland C++: Compile with COMPACT or
- // LARGE memory model with default optimizations.
- //
- // CompuServe: 70714,3113
- // YCCMR BBS: (708)358-5611
- //
- //-------------------------------------------------------------------------
-
- #include <fstream.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include <math.h>
- #include <values.h>
- #include <time.h>
- #include "vector.hpp"
-
- #ifdef __TURBOC__
- #include <graphics.h>
- #include <conio.h>
- #include <dos.h>
- extern unsigned _stklen = 16000; // Larger stack size for recursion
- #endif
-
- typedef enum bool {false = 0, true = 1};
- typedef enum Format {POV, VIVID, RAW};
-
- const char ver[] = "v1.3";
-
- // Function prototypes
- void usage (void);
- void abortmsg (char *msg, int exit_code);
- void add_ext (char *fname, char *ext, bool force);
- void swap (float &a, float &b);
- void process_args (int argc, char *argv[]);
- void file_args (void);
- void process_option (char *s);
- void write_options (void);
- bool read_triangle (Vector&a, Vector&b, Vector&c, int &fix_ab, int &fix_bc,
- int &fix_ca);
- Vector noise_vector (Vector&v);
- void tri_fractal (Vector&a, Vector&b, Vector&c, int fix_ab, int fix_bc,
- int fix_ca, int level, Vector&vmin, Vector&vmax);
- void set_view (void);
- char upcase (char c);
- void plot_tri (const Vector&a, const Vector&b, const Vector&c);
- int init_display (void);
- void close_display (void);
- void check_abort (void);
-
-
- // Global variables
- fstream f, g;
- Vector viewpoint; // Where you're looking from
- Vector lookat; // Where you're looking at
- Vector nx, ny, nz; // Basis vectors for viewpoint
- Vector nscale; // Noise scaling factors
- Vector nbias; // Noise biasing factors
- int depth; // Depth of recursion
- int seed; // Seed for random number generator
- bool display; // Set to true if display preview enabled
- bool swap_yz; // Swap y and z coords on output
- Format format; // Output file format
- char infile[64]; // Input file name
- char outfile[64]; // Output file name
- long tri_count; // Count of triangles generated
- int input_line; // Current input line being parsed
- Vector gmin, gmax;
-
-
- int main (int argc, char* argv[])
- {
- cerr << "\nFractal Landscape Generator " << ver << " ";
- cerr << "Copyright (c) 1992 Steve Anger\n";
- cerr << "This program is freely distributable\n\n";
-
- srand ((unsigned)time(NULL));
- seed = (int)(10000.0 * rand() / (float)RAND_MAX);
- infile[0] = '\0';
- outfile[0] = '\0';
- viewpoint = Vector (10.0, 10.0, -10.0);
- lookat = Vector (0.0, 0.0, 0.0);
- nscale = Vector (0.10, 0.10, 0.10);
- nbias = Vector (0.0, 0.0, 0.0);
- depth = 3;
- display = false;
- swap_yz = false;
- format = POV;
- tri_count = 0;
- input_line = 0;
-
- for (int i = 1; i < argc; i++) {
- if (argv[i][0] != '-' && argv[i][0] != '/') {
- if (infile[0] == '\0') {
- strcpy (infile, argv[i]);
- add_ext (infile, "fr", false);
- }
- else if (outfile[0] == '\0') {
- strcpy (outfile, argv[i]);
-
- }
- else
- abortmsg ("Too many file names specified.", 1);
- }
- }
-
- if (strlen(infile) == 0 || strlen(outfile) == 0) {
- usage();
- exit (1);
- }
-
- f.open (infile, ios::in);
- if (!f) abortmsg ("Error opening input file.", 1);
-
- file_args(); // Get options from input file
-
- process_args (argc, argv); // Get the command line options
-
- switch (format) {
- case POV: add_ext (outfile, "pov", false);
- break;
- case VIVID: add_ext (outfile, "vo", false);
- break;
- case RAW: add_ext (outfile, "raw", false);
- break;
- }
-
- g.open (outfile, ios::out);
- if (!g) abortmsg ("Error opening output file.", 1);
-
- if (depth < 1)
- abortmsg ("Recurse depth (-r) must be >= 1", 1);
-
- cout << "Generating fractal\n";
-
- if (display) {
- set_view();
-
- if (init_display() < 0)
- abortmsg ("Unable to initialize graphics display.", 1);
- }
-
- write_options();
-
- if (format == POV) {
- g << "#declare FracTexture = texture {\n";
- g << " color red 1.0 green 1.0 blue 1.0\n";
- g << " ambient 0.1\n";
- g << " diffuse 0.7\n";
- g << "}\n\n";
-
- g << "composite {\n";
- }
-
- Vector a, b, c, vmin, vmax;
- int fix_ab, fix_bc, fix_ca, tri_read = 0;
-
- Vector gmin = Vector (+MAXFLOAT, +MAXFLOAT, +MAXFLOAT);
- Vector gmax = Vector (-MAXFLOAT, -MAXFLOAT, -MAXFLOAT);
-
- while (read_triangle (a, b, c, fix_ab, fix_bc, fix_ca)) {
- tri_fractal (a, b, c, fix_ab, fix_bc, fix_ca, depth, vmin, vmax);
-
- gmin = min (gmin, vmin);
- gmax = max (gmax, vmax);
- tri_read++;
- }
-
- // Add a bounding box to the entire fractal
- if (format == POV && tri_read > 1) {
- g << "\tbounded_by { box { <" << gmin << "> <" << gmax << "> } }\n";
- g << "}\n\n";
- }
-
- f.close();
- g.close();
-
- cerr << "\n" << tri_count << " triangles generated.\n";
-
- if (display) {
- cerr << "Press return.\n";
- getchar();
- close_display();
- }
-
- return 0;
- }
-
-
- void usage()
- {
- cerr << "Usage: frgen infile[.fr] outfile[.dat] [options]\n";
- cerr << "Options: -sxnnn Scale noise in x direction by nnn (0.0 - 1.0)\n";
- cerr << " -synnn ' ' ' y ' ' ' ' ' \n";
- cerr << " -sznnn ' ' ' z ' ' ' ' ' \n";
- cerr << " -bxnnn Bias noise in x direction by nnn (-1.0 - 1.0)\n";
- cerr << " -bynnn ' ' ' y ' ' ' ' ' \n";
- cerr << " -bznnn ' ' ' z ' ' ' ' ' \n";
- cerr << " -vxnnn Set viewpoint x coord to nnn\n";
- cerr << " -vynnn ' ' y ' ' ' \n";
- cerr << " -vznnn ' ' z ' ' ' \n";
- cerr << " -lxnnn Set lookat x coord to nnn\n";
- cerr << " -lynnn ' ' y ' ' ' \n";
- cerr << " -lznnn ' ' z ' ' ' \n";
- cerr << " -ennn Use nnn as seed for random number generator\n";
- cerr << " -rnnn Maximum recursion depth of nnn\n";
- cerr << " -d Display generated fractal on screen\n";
- cerr << " -o[n] Set output format (-op = PoV, -ov = Vivid, -or = raw)\n";
- cerr << " -x Exchange Y and Z coords on output.\n";
- }
-
-
- void abortmsg (char *msg, int exit_code)
- {
- if (display)
- close_display();
-
- cerr << msg << "\n";
- exit (exit_code);
- }
-
-
- void add_ext (char *fname, char *ext, bool force)
- {
- int i;
-
- for (i = 0; i < strlen(fname); i++)
- if (fname[i] == '.') break;
-
- if (fname[i] == '\0' || force) {
- fname[i] = '.';
- strcpy (&fname[i+1], ext);
- }
- }
-
-
- void swap (float &a, float &b)
- {
- float temp = a;
- a = b;
- b = temp;
- }
-
-
- void process_args (int argc, char* argv[])
- {
- for (int i = 1; i < argc; i++) {
- if (argv[i][0] == '-' || argv[i][0] == '/')
- process_option (&argv[i][1]);
- }
- }
-
-
- void file_args()
- {
- char line[100] = "";
- char last_ch = ' ';
-
- do {
- f.getline (line, 100);
- input_line++;
- } while (!f.eof() && line[0] == ';');
-
- if (f.eof())
- return;
-
- for (int i = 0; i < strlen (line); i++) {
- if ((line[i] == '-' || line[i] == '/') && isspace(last_ch))
- process_option (&line[i+1]);
-
- last_ch = line[i];
- }
- }
-
-
- void process_option (char *s)
- {
- switch (upcase(s[0])) {
- case 'V':
- switch (upcase(s[1])) {
- case 'X': sscanf (&s[2], "%f", &viewpoint.x);
- break;
- case 'Y': sscanf (&s[2], "%f", &viewpoint.y);
- break;
- case 'Z': sscanf (&s[2], "%f", &viewpoint.z);
- break;
- default : cerr << "Invalid option -v" << s[1] << "\n";
- }
- break;
-
- case 'L':
- switch (upcase(s[1])) {
- case 'X': sscanf (&s[2], "%f", &lookat.x);
- break;
- case 'Y': sscanf (&s[2], "%f", &lookat.y);
- break;
- case 'Z': sscanf (&s[2], "%f", &lookat.z);
- break;
- default : cerr << "Invalid option -l" << s[1] << "\n";
- }
- break;
-
- case 'S':
- switch (upcase(s[1])) {
- case 'X': sscanf (&s[2], "%f", &nscale.x);
- break;
- case 'Y': sscanf (&s[2], "%f", &nscale.y);
- break;
- case 'Z': sscanf (&s[2], "%f", &nscale.z);
- break;
- default : cerr << "Invalid option -s" << s[1] << "\n";
- }
- break;
-
- case 'B':
- switch (upcase(s[1])) {
- case 'X': sscanf (&s[2], "%f", &nbias.x);
- break;
- case 'Y': sscanf (&s[2], "%f", &nbias.y);
- break;
- case 'Z': sscanf (&s[2], "%f", &nbias.z);
- break;
- default : cerr << "Invalid option -b" << s[1] << ", ignored\n";
- }
- break;
-
- case 'E': sscanf (&s[1], "%d", &seed);
- break;
-
- case 'R': sscanf (&s[1], "%d", &depth);
- break;
-
- case 'D': display = true;
- break;
-
- case 'X': swap_yz = true;
- break;
-
- case 'O' :
- switch (upcase(s[1])) {
- case 'P': format = POV; break;
- case 'V': format = VIVID; break;
- case 'R': format = RAW; break;
- default : cerr <<"Invalid option -o" << s[1] << ", ignored\n";
- }
- break;
-
-
- default : cerr << "Invalid option -" << s[1] << ", ignored\n";
- }
- }
-
-
- void write_options()
- {
- if (format == POV || format == VIVID) {
- g << "/*\n";
- g << " Generated with FRGEN " << ver << " from file " << infile << "\n";
- g << " Options in effect:";
- g << " -sx" << nscale.x << " -sy" << nscale.y << " -sz" << nscale.z;
- g << " -bx" << nbias.x << " -by" << nbias.y << " -bz" << nbias.z;
- g << " -r" << depth << " -e" << seed << "\n";
- g << "*/\n\n";
- }
- }
-
-
- bool read_triangle (Vector &a, Vector &b, Vector &c,
- int &fix_ab, int &fix_bc, int &fix_ca)
- {
- char line[256] = "";
- char msg[40];
- int n;
-
- do {
- f.getline (line, 256);
- input_line++;
- } while (!f.eof() && line[0] == ';');
-
- if (f.eof())
- return false;
-
- a = Vector (0.0, 0.0, 0.0);
- b = Vector (0.0, 0.0, 0.0);
- c = Vector (0.0, 0.0, 0.0);
-
- fix_ab = 0;
- fix_bc = 0;
- fix_ca = 0;
-
- n = sscanf (line, "%f %f %f %f %f %f %f %f %f %d %d %d",
- &a.x, &a.y, &a.z, &b.x, &b.y, &b.z, &c.x, &c.y, &c.z,
- &fix_ab, &fix_bc, &fix_ca);
-
- if (n == EOF)
- return false;
-
- if (!(n == 9 || n == 12)) {
- sprintf (msg, "Error in input file, line %d", input_line);
- abortmsg (msg, 1);
- }
-
- return true;
- }
-
-
- Vector noise_vector (Vector &v)
- {
- // Generate a random vector that is a function of the
- // vector v's position
- Vector noise;
-
- // seed the rand # generator with a mish-mash of the x, y, and z coords
- srand (seed ^ (long)(-23465*v.x) ^ (long)(17365*v.y) ^ (long)(5364*v.z));
-
- noise.x = nscale.x * (2.0*rand()/RAND_MAX - 1.0 + nbias.x);
- noise.y = nscale.y * (2.0*rand()/RAND_MAX - 1.0 + nbias.y);
- noise.z = nscale.z * (2.0*rand()/RAND_MAX - 1.0 + nbias.z);
-
- return noise;
- }
-
-
- void tri_fractal (Vector &a, Vector &b, Vector &c,
- int fix_ab, int fix_bc, int fix_ca, int level,
- Vector &vmin, Vector &vmax)
- {
- Vector ab, bc, ca;
- float ab_len, bc_len, ca_len;
-
- vmin = Vector (+MAXFLOAT, +MAXFLOAT, +MAXFLOAT);
- vmax = Vector (-MAXFLOAT, -MAXFLOAT, -MAXFLOAT);
-
- if (level == 0) {
- check_abort();
-
- if (swap_yz) {
- swap (a.y, a.z);
- swap (b.y, b.z);
- swap (c.y, c.z);
- }
-
- switch (format) {
- case POV:
- g << "\t\ttriangle { <" << a << "> <" << b << "> <" << c << "> }\n";
- break;
-
- case VIVID:
- g << "polygon {\n";
- g << "\tpoints 3\n";
- g << "\tvertex " << a << "\n";
- g << "\tvertex " << b << "\n";
- g << "\tvertex " << c << "\n";
- g << "}\n\n";
- break;
-
- case RAW:
- g << a << " " << b << " " << c << "\n";
- break;
- }
-
- if (swap_yz) {
- swap (a.y, a.z);
- swap (b.y, b.z);
- swap (c.y, c.z);
- }
-
- tri_count++;
-
- if (display)
- plot_tri (a, b, c);
-
- vmin = min (vmin, a);
- vmin = min (vmin, b);
- vmin = min (vmin, c);
-
- vmax = max (vmax, a);
- vmax = max (vmax, b);
- vmax = max (vmax, c);
- }
- else {
- if (format == POV) {
- if (level == 1) {
- g << "\tobject {\n";
- g << "\t\tunion {\n";
- }
- else if (level > 1)
- g << "composite {\n";
- }
-
- // Find the midpoints of the three line segments
- ab = (a + b)/2.0;
- bc = (b + c)/2.0;
- ca = (c + a)/2.0;
-
- ab_len = mag(a - b);
- bc_len = mag(b - c);
- ca_len = mag(c - a);
-
- // Compute the normal to the triangle
- Vector norm = (b - a) * (c - a);
- norm = norm/mag(norm);
-
- // Create some noise proportional to the edge lengths
- Vector noise_ab = ab_len * noise_vector (ab);
- Vector noise_bc = bc_len * noise_vector (bc);
- Vector noise_ca = ca_len * noise_vector (ca);
-
- // Don't let any 'fixed' points move out of the plane
- // of the triangle (remove the noise's normal component)
- if (fix_ab) noise_ab = noise_ab * norm;
- if (fix_bc) noise_bc = noise_bc * norm;
- if (fix_ca) noise_ca = noise_ca * norm;
-
- // Perturb the three vectors
- ab = ab + noise_ab;
- bc = bc + noise_bc;
- ca = ca + noise_ca;
-
- Vector new_min[4], new_max[4];
-
- tri_fractal (a, ab, ca, fix_ab, 0, fix_ca, level-1, new_min[0], new_max[0]);
- tri_fractal (b, bc, ab, fix_bc, 0, fix_ab, level-1, new_min[1], new_max[1]);
- tri_fractal (c, ca, bc, fix_ca, 0, fix_bc, level-1, new_min[2], new_max[2]);
- tri_fractal (ab, bc, ca, 0, 0, 0, level-1, new_min[3], new_max[3]);
-
- for (int i = 0; i < 4; i++) {
- vmin = min (vmin, new_min[i]);
- vmax = max (vmax, new_max[i]);
- }
-
- if (format == POV) {
- if (level == 1) {
- g << "\t\t}\n\n";
-
- g << "\t\ttexture { FracTexture }\n\n";
- g << "\t\tbounded_by { box { <" << vmin << "> <" << vmax << "> } }\n";
- g << "\t}\n\n";
- }
- else if (level > 1) {
- g << "\tbounded_by { box { <" << vmin << "> <" << vmax << "> } }\n";
- g << "}\n";
- }
- }
- }
- }
-
-
- void set_view()
- {
- Vector sky;
-
- sky = Vector (0.0, 1.0, 0.0);
-
- // Calculate a set of base vectors for the new viewpoint
- nz = lookat - viewpoint;
- nz = nz/mag(nz);
-
- ny = sky - nz*(nz.y/(nz % nz));
- ny = ny/mag(ny);
-
- nx = 1.333 * nz * ny;
- }
-
-
- /* Convert character 'c' top upper case */
- char upcase (char c)
- {
- if (c >= 'a' && c <= 'z')
- c = c - 'a' + 'A';
-
- return c;
- }
-
-
- void plot_tri (const Vector &a, const Vector &b, const Vector &c)
- {
- #ifdef __TURBOC__
- Vector pa, pb, pc, ta, tb, tc;
- int ax, ay, bx, by, cx, cy;
-
- ta = a - viewpoint;
- tb = b - viewpoint;
- tc = c - viewpoint;
-
- pa = Vector (ta % nx, ta % ny, ta % nz);
- pb = Vector (tb % nx, tb % ny, tb % nz);
- pc = Vector (tc % nx, tc % ny, tc % nz);
-
- ax = int((0.5*pa.x/pa.z + 0.5)*getmaxx());
- bx = int((0.5*pb.x/pb.z + 0.5)*getmaxx());
- cx = int((0.5*pc.x/pc.z + 0.5)*getmaxx());
- ay = int((0.5 - pa.y/pa.z)*getmaxy());
- by = int((0.5 - pb.y/pb.z)*getmaxy());
- cy = int((0.5 - pc.y/pc.z)*getmaxy());
-
- setcolor (LIGHTBLUE);
- moveto (ax, ay);
- lineto (bx, by);
- lineto (cx, cy);
- lineto (ax, ay);
- #endif
- }
-
-
- int init_display()
- {
- #ifdef __TURBOC__
- int gdriver = DETECT, gmode, errorcode;
-
- initgraph (&gdriver, &gmode, "");
- errorcode = graphresult();
- if (errorcode != grOk) {
- cerr << "ERROR:" << grapherrormsg (errorcode) << "\n\n";
- return -1;
- }
- #endif
-
- return 0;
- }
-
-
- void close_display()
- {
- #ifdef __TURBOC__
- restorecrtmode();
- #endif
- }
-
-
- void check_abort()
- {
- #ifdef __TURBOC__
- static int cnt = 0;
-
- ++cnt;
-
- if (cnt >= 10) {
- cnt = 0;
-
- if (kbhit())
- abortmsg ("Aborted!", 1);
- }
- #endif
- }
-
-
-